#!make
###############################################################################
# author: Wangliliang
# date: 2011/3/12
# email: postwangliliang@163.com
# any bug or issue please contact me
###############################################################################
#--------------------------------------
#DEBUG flag to control "-g -pg" option
#0-- to disable, 1-- to enable
#DEBUG = 1
#--------------------------------------
#to set the default compiler, default use c++
GCC ?= c++
AR ?= ar
#--------------------------------------
#here you can set your customer macros defined for compiler
#DEFINE_OPTION ?= -DDEBUG
GLOBAL_OPTION ?=
STATIC_LINK ?= 0
#--------------------------------------
#you can add the third part lib's include directories here, lib's developed by yourself should linked in "sub" directory
#INCLUDE_OPTION =
#--------------------------------------
#you can add the third part lib's lib directories here, lib's developed by yourself should linked in "sub" directory
#LIB_OPTION =
#--------------------------------------
install_dir ?= ./
recurse ?= 0
###############################################################################
MODULE_DIR=$(shell pwd)
MODULE=$(notdir $(MODULE_DIR))
#--------------------------------------
OUTER_DEPENDS=$(shell if [ -e dep ]; then ls dep; fi)
DEPEND_MODULES=$(wildcard sub/*)
DEPEND_LIBS=$(foreach MODULE,$(DEPEND_MODULES),$(MODULE)/lib/lib$(notdir $(MODULE)).a)
DEPEND_INCLUDE_OPTION=$(foreach MODULE,$(DEPEND_MODULES),$(shell make --no-print-directory -s -C $(MODULE) show_include))
DEPEND_LIB_OPTION=$(foreach MODULE,$(DEPEND_MODULES),$(shell make --no-print-directory -s -C $(MODULE) show_lib))
#--------------------------------------
CPP_FILES = $(wildcard cpp/*.cpp)
C_FILES = $(wildcard c/*.c)
CPP_OBJS = $(foreach FILE,$(CPP_FILES:.cpp=.o),tmp/$(FILE))
C_OBJS = $(foreach FILE,$(C_FILES:.c=.o),tmp/$(FILE))
CPP_DEPENDS = $(CPP_OBJS:.o=.d)
C_DEPENDS = $(C_OBJS:.o=.d)
MAIN_FILES = $(wildcard main/*.cpp)
MAIN_C_FILES = $(wildcard main/*.c)
MAIN_OBJS = $(foreach FILE, $(MAIN_FILES:.cpp=.o),tmp/$(FILE))
MAIN_C_OBJS = $(foreach FILE, $(MAIN_C_FILES:.c=.o),tmp/$(FILE))
MAIN_DEPENDS = $(MAIN_OBJS:.o=.d) 
MAIN_C_DEPENDS = $(MAIN_C_OBJS:.o=.d)
MAIN_BINS = $(foreach FILE, $(notdir $(MAIN_FILES:.cpp=.bin)), bin/$(FILE))
MAIN_C_BINS = $(foreach FILE, $(notdir $(MAIN_C_FILES:.c=.bin)), bin/$(FILE))
ALL_SRCS = $(C_FILES) $(CPP_FILES) $(MAIN_C_FILES) $(MAIN_FILES)
ALL_OBJS = $(C_OBJS) $(CPP_OBJS) $(MAIN_C_OBJS) $(MAIN_OBJS)
ALL_DEPENDS = $(CPP_DEPENDS) $(C_DEPENDS) $(MAIN_DEPENDS) $(MAIN_C_DEPENDS)
#--------------------------------------
LOCAL_LIB=lib/lib$(MODULE).a
ifeq (,$(CPP_OBJS))
LOCAL_SO=
else
LOCAL_SO=lib/lib$(MODULE).so
endif

LOCAL_LIBS=$(LOCAL_LIB) $(LOCAL_SO)
###############################################################################
#--------------------------------------
ifeq (1,$(DEBUG))
        DEBUG_OPTION=-g
else
        DEBUG_OPTION=
endif

ifeq (1,$(STATIC_LINK))
	STATIC_OPTION=-static
else
	STATIC_OPTION=
endif
#--------------------------------------
INCLUDE_OPTION+=-I$(MODULE_DIR)/include $(DEPEND_INCLUDE_OPTION)
EXT_LIB_OPTION+=-L$(MODULE_DIR)/lib -l$(MODULE) $(DEPEND_LIB_OPTION) $(LIB_OPTION)
#--------------------------------------
COMPILE_OPTIONS=$(DEBUG_OPTION) $(INCLUDE_OPTION) $(DEFINE_OPTION) $(GLOBAL_OPTION)
LINK_OPTIONS=$(DEBUG_OPTION) $(EXT_LIB_OPTION) $(GLOBAL_OPTION) $(STATIC_OPTION)
#--------------------------------------
COMPILE=$(GCC) -c -fpic -o $@ $< $(COMPILE_OPTIONS)
LINK=$(GCC) -o $@ $< $(LINK_OPTIONS)
PACK_LIB=$(AR) -r $@ $^
PACK_SO=$(GCC) -shared -o $@ $^
PACK_CLASS=$(JAR) -cvf $@ -C tmp .
#--------------------------------------
###############################################################################
#--------------------------------------
.PHONY:all dep lib clean create install test help show_include show_lib $(DEPEND_MODULES) $(OUTER_DEPENDS)
#--------------------------------------
all:$(DEPEND_MODULES) lib $(MAIN_BINS) $(MAIN_C_BINS)
#       @echo "make complete!!!"
#--------------------------------------
dep:$(OUTER_DEPENDS)
	@echo "$(MODULE) depends with outer resource $(OUTER_DEPENDS), they are download into sub directory"

$(OUTER_DEPENDS):
	@echo "git clone `readlink dep/$@` ..."
	@if [ -e sub/$@ ]; then cd sub/$@; git pull; cd -; else git clone `readlink dep/$@` sub/$@; fi
#--------------------------------------
$(DEPEND_MODULES):
	make -C $@
#--------------------------------------
lib:$(LOCAL_LIBS)

$(LOCAL_LIB):$(CPP_OBJS) $(C_OBJS)
	mkdir -p lib
	$(PACK_LIB)

$(LOCAL_SO):$(CPP_OBJS) $(C_OBJS)
	mkdir -p lib
	$(PACK_SO)

#--------------------------------------
$(MAIN_C_BINS) $(MAIN_BINS):bin/%.bin:tmp/main/%.o $(LOCAL_LIB)
	mkdir -p bin
	$(LINK)
#--------------------------------------
clean:
	@if [ $(recurse) != 0 ]; then for dir in $(DEPEND_MODULES); do make -C $$dir clean; done; fi
	rm -f $(MAIN_BINS)
	if [ -d cpp -o -d c ]; then rm -f $(LOCAL_LIBS); fi
	rm -rf tmp
#--------------------------------------
create:
	mkdir -p include
	mkdir -p cpp
	mkdir -p main
	mkdir -p sub
	mkdir -p dep
#--------------------------------------
release:
	@if [ $(recurse) != 0 ]; then for dir in $(DEPEND_MODULES); do make -C $$dir release install_dir=$(install_dir); done; fi
	mkdir -p $(install_dir); for file in $(LOCAL_SO); do cp $$file $(install_dir); done

install:
	#@echo back up $(install_dir) as $(install_dir).`date "+%FT%T"`
	#mv $(install_dir) $(install_dir).`date "+%FT%T"`
	@if [ $(recurse) != 0 ]; then for dir in $(DEPEND_MODULES); do make -C $$dir install install_dir=$(install_dir); done; fi
	mkdir -p $(install_dir)
	if [ -e bin ]; then mkdir -p $(install_dir)/bin; cp -r bin/ $(install_dir); fi
	if [ -e data ]; then mkdir -p $(install_dir)/data; cp -r data/ $(install_dir); fi
	if [ -e conf ]; then mkdir -p $(install_dir)/conf; cp -r conf/ $(install_dir); fi
	mkdir -p $(install_dir)/lib; cp -r lib/ $(install_dir) 
	mkdir -p $(install_dir)/include; cp -r include/ $(install_dir)
#	export PATH=$(PATH):`cd $(install_dir)/bin/ && pwd`
#--------------------------------------
test:
	make install install_dir=test
#--------------------------------------
help:
	@echo when you start your project, you can use \"make create\" to create a empty project for you
	@echo it will create following sub directories for you:
	@echo 	include
	@echo 	cpp
	@echo	lib
	@echo 	main
	@echo	sub
	@echo you should put your classes \".h\" files into \"include\" directory and implement source code in \"cpp\" directory
	@echo in \"main\" directory, we put main.cpp and test code here
	@echo the \"lib\" directory is used to put auto maked lib of cpp files
	@echo and the \"sub\" directory is used to put link of sub modules of this module, you can use \"ln\" make other projects link here
	@echo 
	@echo more make options:
	@echo "	all -- default target, to build the project *.bin s"
	@echo "	lib -- to create lib by cpp files"
	@echo "	clean -- to clean the output *.bin files,temp *.o *.d files, make the project ready for rebuild"
	@echo "	create -- to create a empty project environment,if already created,this command do nothing"
	@echo "	test -- to create or update test environment for project"
	@echo "	help -- to display this help infomation"
	@echo "	show_include -- to display depended libs' include directories options"
	@echo "	show_lib -- to display depended libs' lib directories options"
#--------------------------------------
show_include:
	@echo $(INCLUDE_OPTION)
#--------------------------------------
show_lib:
	@echo $(EXT_LIB_OPTION)
#--------------------------------------
DEBUG:
	if [ $(recurse) != 0 ]; then for dir in $(DEPEND_MODULES); do make -C $$dir $@; done; fi	
	echo $(DEPEND_INCLUDE_OPTION)
	echo $(DEPEND_LIB_OPTION)
	echo $(INCLUDE_OPTION)
	echo $(EXT_LIB_OPTION)
	echo $(ALL_OBJS)
	echo $(ALL_DEPENDS)
	echo $(CPP_DEPENDS)
	echo $(MAIN_DEPENDS)
	echo "MAINC_BINS=$(MAIN_C_BINS)"
	echo "resurse=$(recurse)"
	echo $(LOCAL_LIBS)
	echo $(LOCAL_CLASS)
	echo $(OUTER_DEPENDS)
#--------------------------------------
###############################################################################

